package rabbitmq

import (
	"log"

	"github.com/streadway/amqp"
)

// uri  amqp://账号：密码@地址：端口/vhost
const MQURL = "amqp://imoocuser:imoocuser@94.191.18.219:5672/imooc"

type RabbitMQ struct {
	conn    *amqp.Connection
	channel *amqp.Channel
	// 队列名称
	QueueName string
	// 交换机
	Exchange string
	// key
	Key string
	// 连接信息
	Mqurl string
}

// 创建结构体实例的函数
func NewRabbitMQ(queueName, exchange, key string) *RabbitMQ {
	rabbitmq := &RabbitMQ{
		QueueName: queueName,
		Exchange:  exchange,
		Key:       key,
		Mqurl:     MQURL,
	}
	var err error
	rabbitmq.conn, err = amqp.Dial(rabbitmq.Mqurl)
	rabbitmq.failOnError(err, "Failed to connect to RabbitMQ")
	rabbitmq.channel, err = rabbitmq.conn.Channel()
	rabbitmq.failOnError(err, "get channel error!")
	return rabbitmq
}

// 断开channel和connecion
func (r *RabbitMQ) Destory() {
	r.conn.Close()
	r.channel.Close()
}

// 错误处理函数
func (r *RabbitMQ) failOnError(err error, message string) {
	if err != nil {
		log.Fatalf("%s:%s", err, message)
	}
}

// RabbitMQ的简单工作模式
func NewSimpleRabbitMQ(queueName string) *RabbitMQ {
	// 简单模式是：默认交换机，空key
	return NewRabbitMQ(queueName, "", "")
}

// 简单模式下的消息生产代码
func (r *RabbitMQ) PublishSimple(message string) {
	// 申请队列,该操作是幂等的，无需担心重复申请带来的副作用
	_, err := r.channel.QueueDeclare(
		r.QueueName, // 队列名称name
		false,       // 是否持久化 durable
		false,       // 如果未使用，是否自动删除autoDelete
		false,       // 是否具有排他性，其他人不能访问队列exclusive
		false,       // 是否阻塞 noWait
		nil,         //额外属性

	)
	r.failOnError(err, "Failed to declare a queue")
	err = r.channel.Publish(
		r.Exchange,
		r.QueueName, //routing key,一般是目标队列名
		false,
		false,
		amqp.Publishing{
			ContentType: "text/plain",
			Body:        []byte(message),
		},
	)
	r.failOnError(err, "Failed to publish a message")
}

// 简单模式下消费消息代码
func (r *RabbitMQ) ConsumeSimple() {
	// 申请队列,该操作是幂等的，无需担心重复申请带来的副作用
	_, err := r.channel.QueueDeclare(
		r.QueueName, // 队列名称name
		false,       // 是否持久化 durable
		false,       // 如果未使用，是否自动删除autoDelete
		false,       // 是否具有排他性，其他人不能访问队列exclusive
		false,       // 是否阻塞 noWait
		nil,         //额外属性
	)
	r.failOnError(err, "Failed to declare a queue")
	msgs, err := r.channel.Consume(
		r.QueueName,
		"",
		true,
		false,
		false,
		false,
		nil,
	)
	r.failOnError(err, "Failed to comsume a message")

	forever := make(chan bool)
	go func() {
		for d := range msgs {
			log.Printf("Receive a message:%s", d.Body)
		}
	}()
	log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
	<-forever
}
